"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = generateSelector;
exports.selectBaseProps = selectBaseProps;

var _vue = require("vue");

var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _KeyCode = _interopRequireDefault(require("../_util/KeyCode"));

var _classNames3 = _interopRequireDefault(require("../_util/classNames"));

var _Selector = _interopRequireDefault(require("./Selector"));

var _SelectTrigger = _interopRequireDefault(require("./SelectTrigger"));

var _generator = require("./interface/generator");

var _commonUtil = require("./utils/commonUtil");

var _TransBtn = _interopRequireDefault(require("./TransBtn"));

var _useLock3 = _interopRequireDefault(require("./hooks/useLock"));

var _useDelayReset3 = _interopRequireDefault(require("./hooks/useDelayReset"));

var _valueUtil = require("./utils/valueUtil");

var _useSelectTriggerControl = _interopRequireDefault(require("./hooks/useSelectTriggerControl"));

var _useCacheDisplayValue = _interopRequireDefault(require("./hooks/useCacheDisplayValue"));

var _useCacheOptions = _interopRequireDefault(require("./hooks/useCacheOptions"));

var _createRef = _interopRequireDefault(require("../_util/createRef"));

var _vueTypes = _interopRequireDefault(require("../_util/vue-types"));

var _warning = _interopRequireDefault(require("../_util/warning"));

var _isMobile = _interopRequireDefault(require("../vc-util/isMobile"));

var _propsUtil = require("../_util/props-util");

/**
 * To match accessibility requirement, we always provide an input in the component.
 * Other element will not set `tabindex` to avoid `onBlur` sequence problem.
 * For focused select, we set `aria-live="polite"` to update the accessibility content.
 *
 * ref:
 * - keyboard: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#Keyboard_interactions
 */
var __rest = void 0 && (void 0).__rest || function (s, e) {
  var t = {};

  for (var p in s) {
    if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  }

  if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
    if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  }
  return t;
};

var DEFAULT_OMIT_PROPS = ['children', 'removeIcon', 'placeholder', 'autofocus', 'maxTagCount', 'maxTagTextLength', 'maxTagPlaceholder', 'choiceTransitionName', 'onInputKeyDown', 'tabindex'];

function selectBaseProps() {
  return {
    prefixCls: String,
    id: String,
    // Options
    options: {
      type: Array
    },
    mode: {
      type: String
    },
    // Value
    value: {
      type: [String, Number, Object, Array],
      default: undefined
    },
    defaultValue: {
      type: [String, Number, Object, Array],
      default: undefined
    },
    labelInValue: {
      type: Boolean,
      default: undefined
    },
    fieldNames: {
      type: Object
    },
    // Search
    inputValue: String,
    searchValue: String,
    optionFilterProp: String,

    /**
     * In Select, `false` means do nothing.
     * In TreeSelect, `false` will highlight match item.
     * It's by design.
     */
    filterOption: {
      type: [Boolean, Function],
      default: undefined
    },
    filterSort: {
      type: Function
    },
    showSearch: {
      type: Boolean,
      default: undefined
    },
    autoClearSearchValue: {
      type: Boolean,
      default: undefined
    },
    onSearch: {
      type: Function
    },
    onClear: {
      type: Function
    },
    // Icons
    allowClear: {
      type: Boolean,
      default: undefined
    },
    clearIcon: _vueTypes.default.any,
    showArrow: {
      type: Boolean,
      default: undefined
    },
    inputIcon: _vueTypes.default.any,
    removeIcon: _vueTypes.default.any,
    menuItemSelectedIcon: _vueTypes.default.any,
    // Dropdown
    open: {
      type: Boolean,
      default: undefined
    },
    defaultOpen: {
      type: Boolean,
      default: undefined
    },
    listHeight: Number,
    listItemHeight: Number,
    dropdownStyle: {
      type: Object
    },
    dropdownClassName: String,
    dropdownMatchSelectWidth: {
      type: [Boolean, Number],
      default: undefined
    },
    placement: {
      type: String
    },
    virtual: {
      type: Boolean,
      default: undefined
    },
    dropdownRender: {
      type: Function
    },
    dropdownAlign: _vueTypes.default.any,
    animation: String,
    transitionName: String,
    getPopupContainer: {
      type: Function
    },
    direction: {
      type: String
    },
    // Others
    disabled: {
      type: Boolean,
      default: undefined
    },
    loading: {
      type: Boolean,
      default: undefined
    },
    autofocus: {
      type: Boolean,
      default: undefined
    },
    defaultActiveFirstOption: {
      type: Boolean,
      default: undefined
    },
    notFoundContent: _vueTypes.default.any,
    placeholder: _vueTypes.default.any,
    backfill: {
      type: Boolean,
      default: undefined
    },

    /** @private Internal usage. Do not use in your production. */
    getInputElement: {
      type: Function
    },
    optionLabelProp: String,
    maxTagTextLength: Number,
    maxTagCount: {
      type: [String, Number]
    },
    maxTagPlaceholder: _vueTypes.default.any,
    tokenSeparators: {
      type: Array
    },
    tagRender: {
      type: Function
    },
    showAction: {
      type: Array
    },
    tabindex: {
      type: [Number, String]
    },
    // Events
    onKeyup: {
      type: Function
    },
    onKeydown: {
      type: Function
    },
    onPopupScroll: {
      type: Function
    },
    onDropdownVisibleChange: {
      type: Function
    },
    onSelect: {
      type: Function
    },
    onDeselect: {
      type: Function
    },
    onInputKeyDown: {
      type: Function
    },
    onClick: {
      type: Function
    },
    onChange: {
      type: Function
    },
    onBlur: {
      type: Function
    },
    onFocus: {
      type: Function
    },
    onMousedown: {
      type: Function
    },
    onMouseenter: {
      type: Function
    },
    onMouseleave: {
      type: Function
    },
    // Motion
    choiceTransitionName: String,
    // Internal props

    /**
     * Only used in current version for internal event process.
     * Do not use in production environment.
     */
    internalProps: {
      type: Object,
      default: undefined
    },
    children: {
      type: Array
    }
  };
}

var Helper = /*#__PURE__*/(0, _createClass2.default)(function Helper() {
  (0, _classCallCheck2.default)(this, Helper);
  this.SelectBaseProps = selectBaseProps();
});
/**
 * This function is in internal usage.
 * Do not use it in your prod env since we may refactor this.
 */

function generateSelector(config) {
  var defaultPrefixCls = config.prefixCls,
      OptionList = config.components.optionList,
      convertChildrenToData = config.convertChildrenToData,
      flattenOptions = config.flattenOptions,
      getLabeledValue = config.getLabeledValue,
      filterOptions = config.filterOptions,
      isValueDisabled = config.isValueDisabled,
      findValueOption = config.findValueOption,
      warningProps = config.warningProps,
      fillOptionsWithMissingValue = config.fillOptionsWithMissingValue,
      omitDOMProps = config.omitDOMProps;
  var Select = (0, _vue.defineComponent)({
    name: 'Select',
    slots: ['option'],
    inheritAttrs: false,
    props: selectBaseProps(),
    setup: function setup(props, _ref) {
      var expose = _ref.expose,
          attrs = _ref.attrs,
          slots = _ref.slots;
      var useInternalProps = (0, _vue.computed)(function () {
        return props.internalProps && props.internalProps.mark === _generator.INTERNAL_PROPS_MARK;
      });
      (0, _warning.default)(props.optionFilterProp !== 'children', 'Select', 'optionFilterProp not support children, please use label instead');
      var containerRef = (0, _vue.ref)();
      var triggerRef = (0, _vue.ref)();
      var selectorRef = (0, _vue.ref)();
      var listRef = (0, _vue.ref)();
      var tokenWithEnter = (0, _vue.computed)(function () {
        return (props.tokenSeparators || []).some(function (tokenSeparator) {
          return ['\n', '\r\n'].includes(tokenSeparator);
        });
      });
      /** Used for component focused management */

      var _useDelayReset = (0, _useDelayReset3.default)(),
          _useDelayReset2 = (0, _slicedToArray2.default)(_useDelayReset, 3),
          mockFocused = _useDelayReset2[0],
          setMockFocused = _useDelayReset2[1],
          cancelSetMockFocused = _useDelayReset2[2];

      var mergedId = (0, _vue.computed)(function () {
        return props.id || "rc_select_".concat((0, _commonUtil.getUUID)());
      }); // optionLabelProp

      var mergedOptionLabelProp = (0, _vue.computed)(function () {
        var mergedOptionLabelProp = props.optionLabelProp;

        if (mergedOptionLabelProp === undefined) {
          mergedOptionLabelProp = props.options ? 'label' : 'children';
        }

        return mergedOptionLabelProp;
      }); // labelInValue

      var mergedLabelInValue = (0, _vue.computed)(function () {
        return props.mode === 'combobox' ? false : props.labelInValue;
      });
      var isMultiple = (0, _vue.computed)(function () {
        return props.mode === 'tags' || props.mode === 'multiple';
      });
      var mergedShowSearch = (0, _vue.computed)(function () {
        return props.showSearch !== undefined ? props.showSearch : isMultiple.value || props.mode === 'combobox';
      });
      var mobile = (0, _vue.ref)(false);
      (0, _vue.onMounted)(function () {
        mobile.value = (0, _isMobile.default)();
      }); // ============================== Ref ===============================

      var selectorDomRef = (0, _createRef.default)();
      var innerSearchValue = (0, _vue.ref)('');

      var setInnerSearchValue = function setInnerSearchValue(val) {
        innerSearchValue.value = val;
      };

      var mergedValue = (0, _vue.ref)(props.value !== undefined ? props.value : props.defaultValue);
      (0, _vue.watch)(function () {
        return props.value;
      }, function () {
        mergedValue.value = props.value;
        innerSearchValue.value = '';
      }); // ============================= Value ==============================

      /** Unique raw values */

      var mergedRawValueArr = (0, _vue.computed)(function () {
        return (0, _commonUtil.toInnerValue)(mergedValue.value, {
          labelInValue: mergedLabelInValue.value,
          combobox: props.mode === 'combobox'
        });
      });
      var mergedRawValue = (0, _vue.computed)(function () {
        return mergedRawValueArr.value[0];
      });
      var mergedValueMap = (0, _vue.computed)(function () {
        return mergedRawValueArr.value[1];
      });
      /** We cache a set of raw values to speed up check */

      var rawValues = (0, _vue.computed)(function () {
        return new Set(mergedRawValue.value);
      }); // ============================= Option =============================
      // Set by option list active, it will merge into search input when mode is `combobox`

      var activeValue = (0, _vue.ref)();

      var setActiveValue = function setActiveValue(val) {
        activeValue.value = val;
      };

      var mergedSearchValue = (0, _vue.computed)(function () {
        var mergedSearchValue = innerSearchValue.value;

        if (props.mode === 'combobox' && mergedValue.value !== undefined) {
          mergedSearchValue = mergedValue.value;
        } else if (props.searchValue !== undefined) {
          mergedSearchValue = props.searchValue;
        } else if (props.inputValue) {
          mergedSearchValue = props.inputValue;
        }

        return mergedSearchValue;
      });
      var mergedOptions = (0, _vue.computed)(function () {
        var newOptions = props.options;

        if (newOptions === undefined) {
          newOptions = convertChildrenToData(props.children);
        }
        /**
         * `tags` should fill un-list item.
         * This is not cool here since TreeSelect do not need this
         */


        if (props.mode === 'tags' && fillOptionsWithMissingValue) {
          newOptions = fillOptionsWithMissingValue(newOptions, mergedValue.value, mergedOptionLabelProp.value, props.labelInValue);
        }

        return newOptions || [];
      });
      var mergedFlattenOptions = (0, _vue.computed)(function () {
        return flattenOptions(mergedOptions.value, props);
      });
      var getValueOption = (0, _useCacheOptions.default)(mergedFlattenOptions); // Display options for OptionList

      var displayOptions = (0, _vue.computed)(function () {
        if (!mergedSearchValue.value || !mergedShowSearch.value) {
          return (0, _toConsumableArray2.default)(mergedOptions.value);
        }

        var _props$optionFilterPr = props.optionFilterProp,
            optionFilterProp = _props$optionFilterPr === void 0 ? 'value' : _props$optionFilterPr,
            mode = props.mode,
            filterOption = props.filterOption;
        var filteredOptions = filterOptions(mergedSearchValue.value, mergedOptions.value, {
          optionFilterProp: optionFilterProp,
          filterOption: mode === 'combobox' && filterOption === undefined ? function () {
            return true;
          } : filterOption
        });

        if (mode === 'tags' && filteredOptions.every(function (opt) {
          return opt[optionFilterProp] !== mergedSearchValue.value;
        })) {
          filteredOptions.unshift({
            value: mergedSearchValue.value,
            label: mergedSearchValue.value,
            key: '__RC_SELECT_TAG_PLACEHOLDER__'
          });
        }

        if (props.filterSort && Array.isArray(filteredOptions)) {
          return (0, _toConsumableArray2.default)(filteredOptions).sort(props.filterSort);
        }

        return filteredOptions;
      });
      var displayFlattenOptions = (0, _vue.computed)(function () {
        return flattenOptions(displayOptions.value, props);
      });
      (0, _vue.onMounted)(function () {
        (0, _vue.watch)(mergedSearchValue, function () {
          if (listRef.value && listRef.value.scrollTo) {
            listRef.value.scrollTo(0);
          }
        }, {
          flush: 'post',
          immediate: true
        });
      }); // ============================ Selector ============================

      var displayValues = (0, _vue.computed)(function () {
        var tmpValues = mergedRawValue.value.map(function (val) {
          var valueOptions = getValueOption([val]);
          var displayValue = getLabeledValue(val, {
            options: valueOptions,
            prevValueMap: mergedValueMap.value,
            labelInValue: mergedLabelInValue.value,
            optionLabelProp: mergedOptionLabelProp.value
          });
          return (0, _extends2.default)((0, _extends2.default)({}, displayValue), {
            disabled: isValueDisabled(val, valueOptions),
            option: valueOptions[0]
          });
        });

        if (!props.mode && tmpValues.length === 1 && tmpValues[0].value === null && tmpValues[0].label === null) {
          return [];
        }

        return tmpValues;
      }); // Polyfill with cache label

      displayValues = (0, _useCacheDisplayValue.default)(displayValues);

      var triggerSelect = function triggerSelect(newValue, isSelect, source) {
        var newValueOption = getValueOption([newValue]);
        var outOption = findValueOption([newValue], newValueOption, {
          props: props
        })[0];
        var _props$internalProps = props.internalProps,
            internalProps = _props$internalProps === void 0 ? {} : _props$internalProps;

        if (!internalProps.skipTriggerSelect) {
          // Skip trigger `onSelect` or `onDeselect` if configured
          var selectValue = mergedLabelInValue.value ? getLabeledValue(newValue, {
            options: newValueOption,
            prevValueMap: mergedValueMap.value,
            labelInValue: mergedLabelInValue.value,
            optionLabelProp: mergedOptionLabelProp.value
          }) : newValue;

          if (isSelect && props.onSelect) {
            props.onSelect(selectValue, outOption);
          } else if (!isSelect && props.onDeselect) {
            props.onDeselect(selectValue, outOption);
          }
        } // Trigger internal event


        if (useInternalProps.value) {
          if (isSelect && internalProps.onRawSelect) {
            internalProps.onRawSelect(newValue, outOption, source);
          } else if (!isSelect && internalProps.onRawDeselect) {
            internalProps.onRawDeselect(newValue, outOption, source);
          }
        }
      }; // We need cache options here in case user update the option list


      var prevValueOptions = (0, _vue.shallowRef)([]);

      var setPrevValueOptions = function setPrevValueOptions(val) {
        prevValueOptions.value = val;
      };

      var triggerChange = function triggerChange(newRawValues) {
        if (useInternalProps.value && props.internalProps && props.internalProps.skipTriggerChange) {
          return;
        }

        var newRawValuesOptions = getValueOption(newRawValues);
        var outValues = (0, _commonUtil.toOuterValues)(Array.from(newRawValues), {
          labelInValue: mergedLabelInValue.value,
          options: newRawValuesOptions,
          getLabeledValue: getLabeledValue,
          prevValueMap: mergedValueMap.value,
          optionLabelProp: mergedOptionLabelProp.value
        });
        var outValue = isMultiple.value ? outValues : outValues[0]; // Skip trigger if prev & current value is both empty

        if (props.onChange && (mergedRawValue.value.length !== 0 || outValues.length !== 0)) {
          var outOptions = findValueOption(newRawValues, newRawValuesOptions, {
            prevValueOptions: prevValueOptions.value,
            props: props
          }); // We will cache option in case it removed by ajax

          setPrevValueOptions(outOptions.map(function (option, index) {
            var clone = (0, _extends2.default)({}, option);
            Object.defineProperty(clone, '_INTERNAL_OPTION_VALUE_', {
              get: function get() {
                return newRawValues[index];
              }
            });
            return clone;
          }));
          props.onChange(outValue, isMultiple.value ? outOptions : outOptions[0]);
        }

        if (props.value === undefined) {
          mergedValue.value = outValue;
        }
      };

      var onInternalSelect = function onInternalSelect(newValue, _ref2) {
        var selected = _ref2.selected,
            source = _ref2.source;
        var _props$autoClearSearc = props.autoClearSearchValue,
            autoClearSearchValue = _props$autoClearSearc === void 0 ? true : _props$autoClearSearc;

        if (props.disabled) {
          return;
        }

        var newRawValue;

        if (isMultiple.value) {
          newRawValue = new Set(mergedRawValue.value);

          if (selected) {
            newRawValue.add(newValue);
          } else {
            newRawValue.delete(newValue);
          }
        } else {
          newRawValue = new Set();
          newRawValue.add(newValue);
        } // Multiple always trigger change and single should change if value changed


        if (isMultiple.value || !isMultiple.value && Array.from(mergedRawValue.value)[0] !== newValue) {
          triggerChange(Array.from(newRawValue));
        } // Trigger `onSelect`. Single mode always trigger select


        triggerSelect(newValue, !isMultiple.value || selected, source); // Clean search value if single or configured

        if (props.mode === 'combobox') {
          setInnerSearchValue(String(newValue));
          setActiveValue('');
        } else if (!isMultiple.value || autoClearSearchValue) {
          setInnerSearchValue('');
          setActiveValue('');
        }
      };

      var onInternalOptionSelect = function onInternalOptionSelect(newValue, info) {
        onInternalSelect(newValue, (0, _extends2.default)((0, _extends2.default)({}, info), {
          source: 'option'
        }));
      };

      var onInternalSelectionSelect = function onInternalSelectionSelect(newValue, info) {
        onInternalSelect(newValue, (0, _extends2.default)((0, _extends2.default)({}, info), {
          source: 'selection'
        }));
      }; // ============================== Open ==============================


      var initOpen = props.open !== undefined ? props.open : props.defaultOpen;
      var innerOpen = (0, _vue.ref)(initOpen);
      var mergedOpen = (0, _vue.ref)(initOpen);

      var setInnerOpen = function setInnerOpen(val) {
        innerOpen.value = props.open !== undefined ? props.open : val;
        mergedOpen.value = innerOpen.value;
      };

      (0, _vue.watch)(function () {
        return props.open;
      }, function () {
        setInnerOpen(props.open);
      }); // Not trigger `open` in `combobox` when `notFoundContent` is empty

      var emptyListContent = (0, _vue.computed)(function () {
        return !props.notFoundContent && !displayOptions.value.length;
      });
      (0, _vue.watchEffect)(function () {
        mergedOpen.value = innerOpen.value;

        if (props.disabled || emptyListContent.value && mergedOpen.value && props.mode === 'combobox') {
          mergedOpen.value = false;
        }
      });
      var triggerOpen = (0, _vue.computed)(function () {
        return emptyListContent.value ? false : mergedOpen.value;
      });

      var onToggleOpen = function onToggleOpen(newOpen) {
        var nextOpen = newOpen !== undefined ? newOpen : !mergedOpen.value;

        if (innerOpen.value !== nextOpen && !props.disabled) {
          setInnerOpen(nextOpen);

          if (props.onDropdownVisibleChange) {
            props.onDropdownVisibleChange(nextOpen);
          }
        }
      };

      (0, _useSelectTriggerControl.default)([containerRef, triggerRef], triggerOpen, onToggleOpen); // ============================= Search =============================

      var triggerSearch = function triggerSearch(searchText, fromTyping, isCompositing) {
        var ret = true;
        var newSearchText = searchText;
        var preSearchValue = mergedSearchValue.value;
        setActiveValue(null); // Check if match the `tokenSeparators`

        var patchLabels = isCompositing ? null : (0, _valueUtil.getSeparatedContent)(searchText, props.tokenSeparators);
        var patchRawValues = patchLabels;

        if (props.mode === 'combobox') {
          // Only typing will trigger onChange
          if (fromTyping) {
            triggerChange([newSearchText]);
          }
        } else if (patchLabels) {
          newSearchText = '';

          if (props.mode !== 'tags') {
            patchRawValues = patchLabels.map(function (label) {
              var item = mergedFlattenOptions.value.find(function (_ref3) {
                var data = _ref3.data;
                return (0, _propsUtil.getTextFromElement)(data[mergedOptionLabelProp.value]) === label;
              });
              return item ? item.data.value : null;
            }).filter(function (val) {
              return val !== null;
            });
          }

          var newRawValues = Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue.value), (0, _toConsumableArray2.default)(patchRawValues))));
          triggerChange(newRawValues);
          newRawValues.forEach(function (newRawValue) {
            triggerSelect(newRawValue, true, 'input');
          }); // Should close when paste finish

          onToggleOpen(false); // Tell Selector that break next actions

          ret = false;
        }

        setInnerSearchValue(newSearchText);

        if (props.onSearch && preSearchValue !== newSearchText) {
          props.onSearch(newSearchText);
        }

        return ret;
      }; // Only triggered when menu is closed & mode is tags
      // If menu is open, OptionList will take charge
      // If mode isn't tags, press enter is not meaningful when you can't see any option


      var onSearchSubmit = function onSearchSubmit(searchText) {
        // prevent empty tags from appearing when you click the Enter button
        if (!searchText || !searchText.trim()) {
          return;
        }

        var newRawValues = Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue.value), [searchText])));
        triggerChange(newRawValues);
        newRawValues.forEach(function (newRawValue) {
          triggerSelect(newRawValue, true, 'input');
        });
        setInnerSearchValue('');
      }; // Close dropdown when disabled change


      (0, _vue.watch)(function () {
        return props.disabled;
      }, function () {
        if (innerOpen.value && !!props.disabled) {
          setInnerOpen(false);
        }
      }, {
        immediate: true
      }); // Close will clean up single mode search text

      (0, _vue.watch)(mergedOpen, function () {
        if (!mergedOpen.value && !isMultiple.value && props.mode !== 'combobox') {
          triggerSearch('', false, false);
        }
      }, {
        immediate: true
      }); // ============================ Keyboard ============================

      /**
       * We record input value here to check if can press to clean up by backspace
       * - null: Key is not down, this is reset by key up
       * - true: Search text is empty when first time backspace down
       * - false: Search text is not empty when first time backspace down
       */

      var _useLock = (0, _useLock3.default)(),
          _useLock2 = (0, _slicedToArray2.default)(_useLock, 2),
          getClearLock = _useLock2[0],
          setClearLock = _useLock2[1]; // KeyDown


      var onInternalKeyDown = function onInternalKeyDown(event) {
        var clearLock = getClearLock();
        var which = event.which;

        if (which === _KeyCode.default.ENTER) {
          // Do not submit form when type in the input
          if (props.mode !== 'combobox') {
            event.preventDefault();
          } // We only manage open state here, close logic should handle by list component


          if (!mergedOpen.value) {
            onToggleOpen(true);
          }
        }

        setClearLock(!!mergedSearchValue.value); // Remove value by `backspace`

        if (which === _KeyCode.default.BACKSPACE && !clearLock && isMultiple.value && !mergedSearchValue.value && mergedRawValue.value.length) {
          var removeInfo = (0, _commonUtil.removeLastEnabledValue)(displayValues.value, mergedRawValue.value);

          if (removeInfo.removedValue !== null) {
            triggerChange(removeInfo.values);
            triggerSelect(removeInfo.removedValue, false, 'input');
          }
        }

        if (mergedOpen.value && listRef.value) {
          listRef.value.onKeydown(event);
        }

        if (props.onKeydown) {
          props.onKeydown(event);
        }
      }; // KeyUp


      var onInternalKeyUp = function onInternalKeyUp(event) {
        if (mergedOpen.value && listRef.value) {
          listRef.value.onKeyup(event);
        }

        if (props.onKeyup) {
          props.onKeyup(event);
        }
      }; // ========================== Focus / Blur ==========================

      /** Record real focus status */


      var focusRef = (0, _vue.ref)(false);

      var onContainerFocus = function onContainerFocus() {
        setMockFocused(true);

        if (!props.disabled) {
          if (props.onFocus && !focusRef.value) {
            props.onFocus(arguments.length <= 0 ? undefined : arguments[0]);
          } // `showAction` should handle `focus` if set


          if (props.showAction && props.showAction.includes('focus')) {
            onToggleOpen(true);
          }
        }

        focusRef.value = true;
      };

      var onContainerBlur = function onContainerBlur() {
        setMockFocused(false, function () {
          focusRef.value = false;
          onToggleOpen(false);
        });

        if (props.disabled) {
          return;
        }

        var searchVal = mergedSearchValue.value;

        if (searchVal) {
          // `tags` mode should move `searchValue` into values
          if (props.mode === 'tags') {
            triggerSearch('', false, false);
            triggerChange(Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue.value), [searchVal]))));
          } else if (props.mode === 'multiple') {
            // `multiple` mode only clean the search value but not trigger event
            setInnerSearchValue('');
          }
        }

        if (props.onBlur) {
          props.onBlur(arguments.length <= 0 ? undefined : arguments[0]);
        }
      };

      (0, _vue.provide)('VCSelectContainerEvent', {
        focus: onContainerFocus,
        blur: onContainerBlur
      });
      var activeTimeoutIds = [];
      (0, _vue.onMounted)(function () {
        activeTimeoutIds.forEach(function (timeoutId) {
          return window.clearTimeout(timeoutId);
        });
        activeTimeoutIds.splice(0, activeTimeoutIds.length);
      });
      (0, _vue.onBeforeUnmount)(function () {
        activeTimeoutIds.forEach(function (timeoutId) {
          return window.clearTimeout(timeoutId);
        });
        activeTimeoutIds.splice(0, activeTimeoutIds.length);
      });

      var onInternalMouseDown = function onInternalMouseDown(event) {
        var target = event.target;
        var popupElement = triggerRef.value && triggerRef.value.getPopupElement(); // We should give focus back to selector if clicked item is not focusable

        if (popupElement && popupElement.contains(target)) {
          var timeoutId = window.setTimeout(function () {
            var index = activeTimeoutIds.indexOf(timeoutId);

            if (index !== -1) {
              activeTimeoutIds.splice(index, 1);
            }

            cancelSetMockFocused();

            if (!mobile.value && !popupElement.contains(document.activeElement)) {
              selectorRef.value.focus();
            }
          });
          activeTimeoutIds.push(timeoutId);
        }

        if (props.onMousedown) {
          props.onMousedown(event);
        }
      }; // ========================= Accessibility ==========================


      var accessibilityIndex = (0, _vue.ref)(0);
      var mergedDefaultActiveFirstOption = (0, _vue.computed)(function () {
        return props.defaultActiveFirstOption !== undefined ? props.defaultActiveFirstOption : props.mode !== 'combobox';
      });

      var onActiveValue = function onActiveValue(active, index) {
        var _ref4 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
            _ref4$source = _ref4.source,
            source = _ref4$source === void 0 ? 'keyboard' : _ref4$source;

        accessibilityIndex.value = index;

        if (props.backfill && props.mode === 'combobox' && active !== null && source === 'keyboard') {
          setActiveValue(String(active));
        }
      }; // ============================= Popup ==============================


      var containerWidth = (0, _vue.ref)(null);
      (0, _vue.onMounted)(function () {
        (0, _vue.watch)(triggerOpen, function () {
          if (triggerOpen.value) {
            var newWidth = Math.ceil(containerRef.value.offsetWidth);

            if (containerWidth.value !== newWidth) {
              containerWidth.value = newWidth;
            }
          }
        }, {
          immediate: true
        });
      });

      var focus = function focus() {
        selectorRef.value.focus();
      };

      var blur = function blur() {
        selectorRef.value.blur();
      };

      expose({
        focus: focus,
        blur: blur,
        scrollTo: function scrollTo() {
          var _a2;

          var _a;

          return (_a = listRef.value) === null || _a === void 0 ? void 0 : (_a2 = _a).scrollTo.apply(_a2, arguments);
        }
      });
      var instance = (0, _vue.getCurrentInstance)();

      var onPopupMouseEnter = function onPopupMouseEnter() {
        // We need force update here since popup dom is render async
        instance.update();
      };

      return function () {
        var _classNames2;

        var _a = (0, _extends2.default)((0, _extends2.default)({}, props), attrs),
            _a$prefixCls = _a.prefixCls,
            prefixCls = _a$prefixCls === void 0 ? defaultPrefixCls : _a$prefixCls,
            id = _a.id,
            open = _a.open,
            defaultOpen = _a.defaultOpen,
            options = _a.options,
            children = _a.children,
            mode = _a.mode,
            value = _a.value,
            defaultValue = _a.defaultValue,
            labelInValue = _a.labelInValue,
            showSearch = _a.showSearch,
            inputValue = _a.inputValue,
            searchValue = _a.searchValue,
            filterOption = _a.filterOption,
            optionFilterProp = _a.optionFilterProp,
            autoClearSearchValue = _a.autoClearSearchValue,
            onSearch = _a.onSearch,
            allowClear = _a.allowClear,
            clearIcon = _a.clearIcon,
            showArrow = _a.showArrow,
            inputIcon = _a.inputIcon,
            menuItemSelectedIcon = _a.menuItemSelectedIcon,
            disabled = _a.disabled,
            loading = _a.loading,
            defaultActiveFirstOption = _a.defaultActiveFirstOption,
            _a$notFoundContent = _a.notFoundContent,
            notFoundContent = _a$notFoundContent === void 0 ? 'Not Found' : _a$notFoundContent,
            optionLabelProp = _a.optionLabelProp,
            backfill = _a.backfill,
            getInputElement = _a.getInputElement,
            getPopupContainer = _a.getPopupContainer,
            placement = _a.placement,
            _a$listHeight = _a.listHeight,
            listHeight = _a$listHeight === void 0 ? 200 : _a$listHeight,
            _a$listItemHeight = _a.listItemHeight,
            listItemHeight = _a$listItemHeight === void 0 ? 20 : _a$listItemHeight,
            animation = _a.animation,
            transitionName = _a.transitionName,
            virtual = _a.virtual,
            dropdownStyle = _a.dropdownStyle,
            dropdownClassName = _a.dropdownClassName,
            dropdownMatchSelectWidth = _a.dropdownMatchSelectWidth,
            dropdownRender = _a.dropdownRender,
            dropdownAlign = _a.dropdownAlign,
            showAction = _a.showAction,
            direction = _a.direction,
            fieldNames = _a.fieldNames,
            tokenSeparators = _a.tokenSeparators,
            tagRender = _a.tagRender,
            onPopupScroll = _a.onPopupScroll,
            onDropdownVisibleChange = _a.onDropdownVisibleChange,
            onFocus = _a.onFocus,
            onBlur = _a.onBlur,
            onKeyup = _a.onKeyup,
            onKeydown = _a.onKeydown,
            onMousedown = _a.onMousedown,
            onChange = _a.onChange,
            onSelect = _a.onSelect,
            onDeselect = _a.onDeselect,
            onClear = _a.onClear,
            _a$internalProps = _a.internalProps,
            internalProps = _a$internalProps === void 0 ? {} : _a$internalProps,
            restProps = __rest(_a, ["prefixCls", "id", "open", "defaultOpen", "options", "children", "mode", "value", "defaultValue", "labelInValue", "showSearch", "inputValue", "searchValue", "filterOption", "optionFilterProp", "autoClearSearchValue", "onSearch", "allowClear", "clearIcon", "showArrow", "inputIcon", "menuItemSelectedIcon", "disabled", "loading", "defaultActiveFirstOption", "notFoundContent", "optionLabelProp", "backfill", "getInputElement", "getPopupContainer", "placement", "listHeight", "listItemHeight", "animation", "transitionName", "virtual", "dropdownStyle", "dropdownClassName", "dropdownMatchSelectWidth", "dropdownRender", "dropdownAlign", "showAction", "direction", "fieldNames", "tokenSeparators", "tagRender", "onPopupScroll", "onDropdownVisibleChange", "onFocus", "onBlur", "onKeyup", "onKeydown", "onMousedown", "onChange", "onSelect", "onDeselect", "onClear", "internalProps"]); //as SelectProps<OptionType[], ValueType>;
        // ============================= Input ==============================
        // Only works in `combobox`


        var customizeInputElement = mode === 'combobox' && getInputElement && getInputElement() || null;
        var domProps = omitDOMProps ? omitDOMProps(restProps) : restProps;
        DEFAULT_OMIT_PROPS.forEach(function (prop) {
          delete domProps[prop];
        });
        var popupNode = (0, _vue.createVNode)(OptionList, {
          "ref": listRef,
          "prefixCls": prefixCls,
          "id": mergedId.value,
          "open": mergedOpen.value,
          "childrenAsData": !options,
          "options": displayOptions.value,
          "fieldNames": fieldNames,
          "flattenOptions": displayFlattenOptions.value,
          "multiple": isMultiple.value,
          "values": rawValues.value,
          "height": listHeight,
          "itemHeight": listItemHeight,
          "onSelect": onInternalOptionSelect,
          "onToggleOpen": onToggleOpen,
          "onActiveValue": onActiveValue,
          "defaultActiveFirstOption": mergedDefaultActiveFirstOption.value,
          "notFoundContent": notFoundContent,
          "onScroll": onPopupScroll,
          "searchValue": mergedSearchValue.value,
          "menuItemSelectedIcon": menuItemSelectedIcon,
          "virtual": virtual !== false && dropdownMatchSelectWidth !== false,
          "onMouseenter": onPopupMouseEnter,
          "direction": direction
        }, slots); // ============================= Clear ==============================

        var clearNode;

        var onClearMouseDown = function onClearMouseDown(e) {
          e.stopPropagation(); // Trigger internal `onClear` event

          if (useInternalProps.value && internalProps.onClear) {
            internalProps.onClear();
          }

          if (onClear) {
            onClear();
          }

          triggerChange([]);
          triggerSearch('', false, false);
        };

        if (!disabled && allowClear && (mergedRawValue.value.length || mergedSearchValue.value)) {
          clearNode = (0, _vue.createVNode)(_TransBtn.default, {
            "class": "".concat(prefixCls, "-clear"),
            "onMousedown": onClearMouseDown,
            "customizeIcon": clearIcon
          }, {
            default: function _default() {
              return [(0, _vue.createTextVNode)("\xD7")];
            }
          });
        } // ============================= Arrow ==============================


        var mergedShowArrow = showArrow !== undefined ? showArrow : loading || !isMultiple.value && mode !== 'combobox';
        var arrowNode;

        if (mergedShowArrow) {
          arrowNode = (0, _vue.createVNode)(_TransBtn.default, {
            "class": (0, _classNames3.default)("".concat(prefixCls, "-arrow"), (0, _defineProperty2.default)({}, "".concat(prefixCls, "-arrow-loading"), loading)),
            "customizeIcon": inputIcon,
            "customizeIconProps": {
              loading: loading,
              searchValue: mergedSearchValue.value,
              open: mergedOpen.value,
              focused: mockFocused.value,
              showSearch: mergedShowSearch.value
            }
          }, null);
        } // ============================ Warning =============================


        if (process.env.NODE_ENV !== 'production' && warningProps) {
          warningProps(props);
        } // ============================= Render =============================


        var mergedClassName = (0, _classNames3.default)(prefixCls, attrs.class, (_classNames2 = {}, (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-focused"), mockFocused.value), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-multiple"), isMultiple.value), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-single"), !isMultiple.value), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-allow-clear"), allowClear), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-show-arrow"), mergedShowArrow), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-disabled"), disabled), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-loading"), loading), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-open"), mergedOpen.value), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-customize-input"), customizeInputElement), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-show-search"), mergedShowSearch.value), _classNames2));
        return (0, _vue.createVNode)("div", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, domProps), {}, {
          "class": mergedClassName,
          "ref": containerRef,
          "onMousedown": onInternalMouseDown,
          "onKeydown": onInternalKeyDown,
          "onKeyup": onInternalKeyUp
        }), [mockFocused.value && !mergedOpen.value && (0, _vue.createVNode)("span", {
          "style": {
            width: 0,
            height: 0,
            display: 'flex',
            overflow: 'hidden',
            opacity: 0
          },
          "aria-live": "polite"
        }, ["".concat(mergedRawValue.value.join(', '))]), (0, _vue.createVNode)(_SelectTrigger.default, {
          "ref": triggerRef,
          "disabled": disabled,
          "prefixCls": prefixCls,
          "visible": triggerOpen.value,
          "popupElement": popupNode,
          "containerWidth": containerWidth.value,
          "animation": animation,
          "transitionName": transitionName,
          "dropdownStyle": dropdownStyle,
          "dropdownClassName": dropdownClassName,
          "direction": direction,
          "dropdownMatchSelectWidth": dropdownMatchSelectWidth,
          "dropdownRender": dropdownRender,
          "dropdownAlign": dropdownAlign,
          "placement": placement,
          "getPopupContainer": getPopupContainer,
          "empty": !mergedOptions.value.length,
          "getTriggerDOMNode": function getTriggerDOMNode() {
            return selectorDomRef.current;
          }
        }, {
          default: function _default() {
            return [(0, _vue.createVNode)(_Selector.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), {}, {
              "domRef": selectorDomRef,
              "prefixCls": prefixCls,
              "inputElement": customizeInputElement,
              "ref": selectorRef,
              "id": mergedId.value,
              "showSearch": mergedShowSearch.value,
              "mode": mode,
              "accessibilityIndex": accessibilityIndex.value,
              "multiple": isMultiple.value,
              "tagRender": tagRender,
              "values": displayValues.value,
              "open": mergedOpen.value,
              "onToggleOpen": onToggleOpen,
              "searchValue": mergedSearchValue.value,
              "activeValue": activeValue.value,
              "onSearch": triggerSearch,
              "onSearchSubmit": onSearchSubmit,
              "onSelect": onInternalSelectionSelect,
              "tokenWithEnter": tokenWithEnter.value
            }), null)];
          }
        }), arrowNode, clearNode]);
      };
    }
  });
  return Select;
}